home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
dev
/
gg
/
bing-1.1.3.lha
/
bing-1.1.3
/
src
/
win32
/
icmp_win32.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-06
|
9KB
|
306 lines
/*
* This module provides an interface to send and receive ICMP messages
* which is closer to the way Unix programs are written than the standard
* WIN32 icmp dll's interface.
*/
#include "win32/win32.h"
#include <winsock.h>
#include "win32/types.h"
#include "netinet/ip.h"
#include "netinet/ip_var.h"
#include "netinet/ip_icmp.h"
#include <ipexport.h>
#include <icmpapi.h>
#include "mod_icmp.h"
#include <malloc.h>
#include <errno.h>
typedef struct {
HANDLE hICMP; /* The ICMP dll handle */
/* "Socket" options */
int rcvbufsize; /* Size of the receive buffer */
struct ip_option_information ip_options;/* The IP options */
unsigned long timeout; /* Time to wait for a reply */
/* A few things to remember about the request */
u_short msg_id;
u_short msg_seq;
/* Some fields to process the answers */
struct icmp_echo_reply* rcvbuf; /* The buffer in which */
/* IcmpSendEcho will store the answers */
int nb_replies; /* -1 => message not sent yet. */
/* >=0 => number of reply messages */
struct icmp_echo_reply* current; /* Pointer to next reply */
LARGE_INTEGER rtt_in_ticks; /* This is our own measurment of the RTT */
LARGE_INTEGER ticks_freq;
} icmp_state_i;
#define handle2state(h) ((icmp_state_i*)h)
icmp_handle icmp_open()
{
icmp_state_i* handle;
/* Perform some initialisation to ease error recovery */
handle=NULL;
/* Give a higher priority so that bing has better
* chances not to be delayed when measuring the RTT.
*/
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
/* Allocate the handle */
handle=malloc(sizeof(icmp_state_i));
/* Fill defaults */
handle->hICMP=IcmpCreateFile();
handle->rcvbufsize=4096;
handle->rcvbuf=NULL;
handle->nb_replies=-1;
QueryPerformanceFrequency(&handle->ticks_freq);
/* Set options defaults */
handle->ip_options.Ttl=255;
handle->ip_options.Tos=0;
handle->ip_options.Flags=0;
handle->ip_options.OptionsSize=0;
handle->ip_options.OptionsData=NULL;
return (icmp_handle)handle;
error:
if (handle!=NULL)
free(handle);
return NULL;
}
int icmp_set_option(icmp_handle handle, int level, int optname, char* optval,
int optlen)
{
int ret;
ret=0;
switch (level) {
case IPPROTO_IP:
/* The IP options are handled by building the
* corresponding IP structure by hand.
*/
/* No IP option is supported yet */
errno=ENOSYS;
ret=-1;
break;
case SOL_SOCKET:
switch (optname) {
case SO_RCVBUF:
handle2state(handle)->rcvbufsize=*((int*)optval);
break;
default:
errno=ENOSYS;
ret=-1;
break;
}
break;
default:
errno=ENOSYS;
ret=-1;
}
return ret;
}
void icmp_set_timeout(icmp_handle handle,unsigned long timeout)
{
handle2state(handle)->timeout=timeout/1000;
}
unsigned short icmp_get_id(icmp_handle handle)
{
return handle2state(handle)->msg_id;
}
int icmp_send(icmp_handle handle, char* msg, int msg_size,
struct sockaddr* to_addr, int to_addr_size)
{
DWORD reply_size;
LARGE_INTEGER start,stop;
static int nb_toohigh=0,nb=0;
static int icmp_min=1000000,query_min=1000000;
/* Record some information for the recv */
handle2state(handle)->msg_id=((struct icmp*)msg)->icmp_id;
handle2state(handle)->msg_seq=((struct icmp*)msg)->icmp_seq;
/* allocate the buffer for the replies */
handle2state(handle)->rcvbuf=realloc(handle2state(handle)->rcvbuf,
handle2state(handle)->rcvbufsize);
QueryPerformanceCounter(&start);
handle2state(handle)->nb_replies=IcmpSendEcho(
handle2state(handle)->hICMP,
*((IPAddr*)&(((struct sockaddr_in*)to_addr)->sin_addr)),
msg+ICMP_MINLEN,
(WORD)(msg_size-ICMP_MINLEN),
&handle2state(handle)->ip_options,
handle2state(handle)->rcvbuf,
handle2state(handle)->rcvbufsize,
handle2state(handle)->timeout
);
QueryPerformanceCounter(&stop);
if ((handle2state(handle)->ticks_freq.QuadPart!=0) &&
(handle2state(handle)->nb_replies==1)) {
/* If we have a high performance counter, use it to measure
* the RTT. The high performance counter will either give us
* a much more precise measure of the RTT than the ICMP
* library or it will give us a gross exageration of the RTT
* if the execution of our process has been delayed by the
* scheduler. Statistically this should give much better
* results than the ICMP library (which tends to sometimes
* under-estimate the RTT by up to nearly 2 ms which is
* BAD in our case.
*/
handle2state(handle)->rtt_in_ticks.QuadPart=
stop.QuadPart-start.QuadPart;
} else
handle2state(handle)->rtt_in_ticks.QuadPart=0;
if (handle2state(handle)->nb_replies==0) {
if (GetLastError()==IP_REQ_TIMED_OUT)
return 0;
printf("icmp_send: error %d\n",GetLastError());
errno=GetLastError();
return -1;
}
handle2state(handle)->current=handle2state(handle)->rcvbuf;
return msg_size;
}
int icmp_recv(icmp_handle handle, char* buffer, int buffer_size,
struct sockaddr* from_addr, int* from_addr_size,
double* elapsed)
{
if (handle2state(handle)->nb_replies>0) {
struct ip* ip_msg;
struct icmp* icmp_msg;
/* Misc return values */
((struct sockaddr_in*)from_addr)->sin_family=AF_INET;
((struct sockaddr_in*)from_addr)->sin_port=0;
memcpy(&(((struct sockaddr_in*)from_addr)->sin_addr),
&handle2state(handle)->current->Address,4);
if (handle2state(handle)->rtt_in_ticks.QuadPart==0)
*elapsed=(double)(handle2state(handle)->current->RoundTripTime);
else
*elapsed=((double)(handle2state(handle)->rtt_in_ticks.QuadPart*1000))/
handle2state(handle)->ticks_freq.QuadPart;
/* Reconstruct the ip header */
ip_msg=(struct ip*)buffer;
ip_msg->ip_v=4;
ip_msg->ip_hl=(sizeof(struct ip)
+handle2state(handle)->current->Options.OptionsSize) >> 2;
ip_msg->ip_tos=handle2state(handle)->current->Options.Tos;
ip_msg->ip_len=((ip_msg->ip_hl) << 2)
+ICMP_MINLEN
+handle2state(handle)->current->DataSize;
ip_msg->ip_id=0;
ip_msg->ip_off=0;
ip_msg->ip_ttl=handle2state(handle)->current->Options.Ttl;
ip_msg->ip_p=0;
ip_msg->ip_sum=0;
memcpy(&(ip_msg->ip_src),&handle2state(handle)->current->Address,4);
memset(&ip_msg->ip_dst,0,4);
if (handle2state(handle)->current->Options.OptionsSize>0)
memcpy(buffer+sizeof(struct ip),
handle2state(handle)->current->Options.OptionsData,
handle2state(handle)->current->Options.OptionsSize);
/* Reconstruct the icmp header */
icmp_msg=(struct icmp*)(buffer+((ip_msg->ip_hl) << 2));
switch (handle2state(handle)->current->Status) {
/* Echo Reply (what we expect) */
case IP_SUCCESS:
icmp_msg->icmp_type=0;
icmp_msg->icmp_code=0;
icmp_msg->icmp_id=handle2state(handle)->msg_id;
icmp_msg->icmp_seq=handle2state(handle)->msg_seq;
break;
/* Destination Unreachable */
case IP_DEST_NET_UNREACHABLE:
icmp_msg->icmp_type=3;
icmp_msg->icmp_code=0;
break;
case IP_DEST_HOST_UNREACHABLE:
icmp_msg->icmp_type=3;
icmp_msg->icmp_code=1;
break;
case IP_DEST_PROT_UNREACHABLE:
icmp_msg->icmp_type=3;
icmp_msg->icmp_code=2;
break;
case IP_DEST_PORT_UNREACHABLE:
icmp_msg->icmp_type=3;
icmp_msg->icmp_code=3;
break;
/* Time Exceeded */
case IP_TTL_EXPIRED_TRANSIT:
icmp_msg->icmp_type=11;
icmp_msg->icmp_code=0;
break;
case IP_TTL_EXPIRED_REASSEM:
icmp_msg->icmp_type=11;
icmp_msg->icmp_code=1;
break;
/* Parameter Problem */
case IP_PARAM_PROBLEM:
icmp_msg->icmp_type=12;
icmp_msg->icmp_code=0;
/* how can I get a value for the pointer field ? */
break;
/* Source Quench */
case IP_SOURCE_QUENCH:
icmp_msg->icmp_type=4;
icmp_msg->icmp_code=0;
break;
default:
handle2state(handle)->nb_replies--;
handle2state(handle)->current++;
return -handle2state(handle)->current->Status;
}
/* Who cares about the checksum ? */
icmp_msg->icmp_cksum=0;
/* Copy data */
memcpy(buffer+((ip_msg->ip_hl) << 2)+ICMP_MINLEN,
handle2state(handle)->current->Data,
handle2state(handle)->current->DataSize);
handle2state(handle)->nb_replies--;
handle2state(handle)->current++;
return ip_msg->ip_len;
} else
return 0;
}
int icmp_close(icmp_handle handle)
{
int ret;
ret=IcmpCloseHandle((HANDLE)(((icmp_state_i*)handle)->hICMP));
free(handle);
return (ret?0:-1);
}